#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
#include <algorithm>
using namespace std;

vector<vector<int>> memo;
int dfs(vector<vector<char>>& v, unordered_map<char, int>& p, int i, int j) {
    // 正确处理越界情况：只要i或j有一个越界，就返回0
    if (i >= v.size() || j >= v[0].size()) {
        return 0;
    }

    // 已计算过的状态直接返回
    if (memo[i][j] != -1) {
        return memo[i][j];
    }

    // 当前格子的分值
    int current = p[v[i][j]];

    // 计算向右和向下的最大分值
    int right = dfs(v, p, i, j + 1);
    int down = dfs(v, p, i + 1, j);

    // 取最大值并加上当前分值
    memo[i][j] = current + max(right, down);
    return memo[i][j];
}

int main() {
    int n, m;
    cin >> n >> m;

    // 处理空网格情况
    if (n == 0 || m == 0) {
        cout << 0 << endl;
        return 0;
    }

    // 正确初始化二维vector，确保每行有m个元素
    vector<vector<char>> v(n, vector<char>(m));
    for (int i = 0; i < n; i++) {
        string str;
        cin >> str;
        for (int j = 0; j < m; j++) {
            v[i][j] = str[j];
        }
    }

    unordered_map<char, int> p;
    p['l'] = 4;
    p['o'] = 3;
    p['v'] = 2;
    p['e'] = 1;

    // 初始化备忘录
    memo.assign(n, vector<int>(m, -1));

    // 输出结果
    cout << dfs(v, p, 0, 0) << endl;

    return 0;
}
